function TestCtrl($scope) {
  $scope.tests = {
    'question_1': {
      expected: 'p&q',
      actual: displayExpression(buildQuestion(' ', 'p&q', BASE_STUDENT_LANGUAGE, BASE_VOCABULARY).results[0], BASE_STUDENT_LANGUAGE.operators)
    },
    'question_2': {
      expected: 'f(2)=3, @x.(x>1)',
      actual: displayExpressionArray(buildQuestion('f(2)=3,@x.x>1', 'p&q', BASE_STUDENT_LANGUAGE, BASE_VOCABULARY).assumptions, BASE_STUDENT_LANGUAGE.operators)
    },
    'question_3': {
      error: 'f must have 1 arguments.',
      actual: function() {buildQuestion('f(x,y)=z', 'f(x)=z', BASE_STUDENT_LANGUAGE, BASE_VOCABULARY);}
    },
    'question_4': {
      error: 'The name \'we\' is reserved for vocabulary and so cannot be used here.',
      actual: function() {
        buildQuestion('we&you', 'p=q', BASE_STUDENT_LANGUAGE, BASE_VOCABULARY)
      }
    },    
    'line_template_1': {
      expected: JSON.stringify(["and_introduce","from p and q we have p&q","p, q","p&q",""]),
      actual: JSON.stringify(displayLineTemplate(
        buildLineTemplate('and_introduce', 'from p and q we have p&q', 'p, q', 'p&q', '', [], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY), 
        BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY))
    },
    'line_template_2': {
      expected: JSON.stringify(
        [
          'and_introduce', 'from p we have p&q', 'p', 'p&q', '',
          'Should this be "from {{p}} and {{q}} we have {{p&q}}"?', 
          'To prove {{p&q}} you need to have shown {{q}} as well'
        ]),
      actual: JSON.stringify(displayLineTemplate(
        buildLineTemplate(
          'and_introduce', 'from p we have p&q', 'p', 'p&q', '',
          [
            'Should this be "from {{p}} and {{q}} we have {{p&q}}"?', 
            'To prove {{p&q}} you need to have shown {{q}} as well'
          ], 
          BASE_STUDENT_LANGUAGE, BASE_VOCABULARY), 
        BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY))
    },
    'line_template_3': {
      expected: JSON.stringify(['for_all_introduce', '{{a|element}} was arbitrary hence @x.p', 'p[x->a]', '@x.p', 'a']),
      actual: JSON.stringify(displayLineTemplate(
        buildLineTemplate('for_all_introduce', '{{a|element}} was arbitrary hence @x.p', 'p[x->a]', '@x.p', 'a', [], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY), 
        BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY))
    },
    'line_template_4': {
      error: 'It will not be possible to uniquely identify p from a line of this form.',
      actual: function() {
        buildLineTemplate('name', 'from q we have r', 'q', 'p', '', [], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY)
      }
    },
    'line_template_5': {
      // FUTURE: render this test passable
      error: 'It will not be possible to uniquely identify a from a line of this form.',
      actual: function() {
        buildLineTemplate('exists_introduce', 'from p[x->a] we have $x.p', 'p[x->a]', '$x.p', 'a', [], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY)
      }
    },
    'line_template_6': {
      error: 'p yields a boolean but you are trying to use it to give a element.',
      actual: function() {
        buildLineTemplate('name', 'take p satisfying q[x->p]', '', '', '', [], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY)
      }
    },
    'line_template_table_1': {
      expected: JSON.stringify([
        ["a","p hence q","p","q",""],
        ["b","$x.(p&q) if a contradiction we have from r","r, p, q","","x","How unwise {{x|variable}}."]
      ]),
      actual: JSON.stringify(displayLineTemplateTable(buildLineTemplateTable([{
        name: 'a',
        reader_view: 'p hence q',
        antecedents: 'p',
        results: 'q',
        variables: '',
        errors: []
      }, {
        name: 'b',
        reader_view: '$x.p&q if a contradiction we have from r',
        antecedents: 'r, p, q',
        results: '',
        variables: 'x',
        errors: ['How unwise {{x|variable}}.']        
      }], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY, DEFAULT_ERROR_MESSAGES), BASE_STUDENT_LANGUAGE.operators, BASE_VOCABULARY))
    },
    'line_template_table_2': {
      error: 'The name \'if\' is reserved for vocabulary and so cannot be used here.',
      actual: function() {
          buildLineTemplateTable([{
          name: 'a',
          reader_view: 'p hence q',
          antecedents: 'p',
          results: 'q',
          variables: '',
          errors: []
        }, {
          name: 'a',
          reader_view: '$x.p& if a contradiction we have from r',
          antecedents: 'r, p, q',
          results: '',
          variables: 'x',
          errors: ['How unwise {{x|variable}}.']        
        }], BASE_STUDENT_LANGUAGE, BASE_VOCABULARY, DEFAULT_ERROR_MESSAGES)
      }
    },
    'mistake_entry_1': {
      expected: JSON.stringify([
        'name',
        '(n=1)&(indentation(n)>0)', 
        'The first line of a proof should not be indented',
        'Don\'t indent the first line of your proof'
      ]),
      actual: JSON.stringify(
        displayMistakeEntry(
          buildMistakeEntry(
            'name', 'n=1 & indentation(n)>0', [
              'The first line of a proof should not be indented',
              'Don\'t indent the first line of your proof'
            ], BASE_CONTROL_LANGUAGE
          ), BASE_CONTROL_LANGUAGE.operators
        )
      )
    },
    'mistake_entry_2': {
      error: 'antecedents yields a set_of_formulas but you are trying to use it to give a integer.',
      actual: function() {
        buildMistakeEntry('name', 'template(n) = \'given\'', ['examine {{antecedents(n-1)+1}}'], BASE_CONTROL_LANGUAGE)
      }
    },
    'mistake_entry_3': {
      expected: JSON.stringify({
        name:'name',
        occurs:{
          operator:'not',
          kind:'unary_connective',
          arguments:[{
            operator:'is_in',
            kind:'binary_relation',
            arguments:[{
              operator:'target',
              kind:'prefix_function',
              arguments:[],
              dummies:[],
              type:'formula'
            },{
              operator:'results',
              kind:'prefix_function',
              arguments:[{
                operator:'n',
                kind:'variable',
                arguments:[],
                dummies:[],
                type:'integer'
              }],
              dummies:[],
              type:'set_of_formulas'
            }],
            dummies:[],
            type:'boolean'
          }],
          dummies:[],
          type:'boolean'
        },
        message:[[{
          format:'expression',
          content:{
            operator:'subtraction',
            kind:'binary_function',
            arguments:[{
              operator:'num_lines',
              kind:'prefix_function',
              arguments:[],
              dummies:[],
              type:'integer'
            },{
              operator:1,
              kind:'constant',
              arguments:[],
              dummies:[],
              type:'integer'
            }],
            dummies:[],
            type:'integer'
          }
        }]]
      }),
      actual: JSON.stringify(
        buildMistakeEntry(
          'name', '~target()?results(n)', ['{{num_lines()-1}}'], 
          BASE_CONTROL_LANGUAGE))
    },
    'mistake_section_1': {
      expected: JSON.stringify({
        name: 'layout',
        entries: [
          ['mistake_1','entry(1,antecedents(n))?assumptions()', 'wrong'], 
          ['mistake_2', 'num_lines()>3', 'Try to assess {{indentation(22)}}']]
      }),
      actual: JSON.stringify(
        displayMistakeSection(
          buildMistakeSection(
            'layout',
            [{
              name: 'mistake_1',
              occurs: 'entry(1,antecedents(n))?assumptions()',
              message: ['wrong']
            }, {
              name: 'mistake_2',
              occurs: 'num_lines()>3',
              message: ['Try to assess {{indentation(22)}}']
            }], BASE_CONTROL_LANGUAGE
          ), BASE_CONTROL_LANGUAGE.operators
        )
      )
    },
    'mistake_section_2': {
      expected: 'The operator operator could not be identified.',
      actual: buildMistakeSection(
        'variables',
        [{
          name: 'a mistake',
          occurs: 'operator(n)=\'and\'',
          message: ['Dear dear']
        }], BASE_CONTROL_LANGUAGE, DEFAULT_ERROR_MESSAGES
        ).failure[0]
    },
    'control_function_1': {
      expected: '{"LHS":"f(n)","RHS":"n+2","description":"a"}',
      actual: JSON.stringify(
        displayControlFunction(
          buildControlFunction('f(n)', 'n+2', 'a', BASE_CONTROL_LANGUAGE).name, 
          buildControlFunction('f(n)', 'n+2', 'a', BASE_CONTROL_LANGUAGE).evaluation_rule, 
          BASE_CONTROL_LANGUAGE.operators
        )
      )
    },
    'control_function_2': {
      expected: '{"LHS":"is_scope_creator(n)","RHS":"(template(n)=\'given\')|(template(n)=\'assumption\')","description":""}',
      actual: JSON.stringify(
        displayControlFunction(
         buildControlFunction('is_scope_creator(n)', 'template(n)=\'given\' | template(n)=\'assumption\'', '', BASE_CONTROL_LANGUAGE).name, 
          buildControlFunction('is_scope_creator(n)', 'template(n)=\'given\' | template(n)=\'assumption\'', '', BASE_CONTROL_LANGUAGE).evaluation_rule, 
          BASE_CONTROL_LANGUAGE.operators
        )
      )
    },
    'control_function_3': {
      error: 'The operator missing_function could not be identified.',
      actual: function() {
        buildControlFunction('bad_function(x,y)', 'missing_function(x-y, x+y)', '', BASE_CONTROL_LANGUAGE)
      }
    },
    'control_function_4': {
      error: 'template yields a string but you are trying to use it to give a integer.',
      actual: function() {
        buildControlFunction('f(n)', 'template(n) + 3', '', BASE_CONTROL_LANGUAGE)
      }
    },
    'control_function_5': {
      error: 'Unfortunately this cannot be accepted as it has multiple possible typings.',
      actual: function() {
        buildControlFunction('f(n)', 'n', '', BASE_CONTROL_LANGUAGE)
      }
    },
    'control_function_6': {
      error: 'You cannot use n as a function name; it is reserved to refer to line numbers',
      actual: function() {
        buildControlFunction('n(x,y)', 'x-y', '', BASE_CONTROL_LANGUAGE)
      }
    },
    'control_function_7': {
      expected: JSON.stringify({
        format:'definition',
        content:{
          operator:'addition',
          kind:'binary_function',
          arguments:[{
            operator:'x',
            kind:'variable',
            arguments:[],
            dummies:[],
            type:'integer'
          },{
            operator:2,
            kind:'constant',
            arguments:[],
            dummies:[],
            type:'integer'
          }],
          dummies:[],
          type:'integer'
        },
        variables:[{
          kind:'variable',
          operator:'x',
          arguments:[],
          dummies:[]
        }],
        description:'a description'
      }),
      actual: JSON.stringify(buildControlFunction('f(x)', 'x+2', 'a description', BASE_CONTROL_LANGUAGE).evaluation_rule)
    },
    'control_function_table_1': {
      expected: JSON.stringify([{
        LHS: 'is_scope_creator(n)',
        RHS: '(template(n)=\'given\')|(template(n)=\'assumption\')',
        description: 'a'
      }, {
        LHS: 'is_in_scope(m,n)',
        RHS: '(~is_scope_creator(m)&((indentation(n)>=indentation(m))&~$k<=n.(k>=m)&(indentation(k)<indentation(m))))|((indentation(n)>indentation(m))&~$k<=n.(k>=m)&(indentation(k)<=indentation(m)))',
        description: 'b'
      }]),
      actual: JSON.stringify(
        displayControlFunctionTable(
          buildControlFunctionTable(
            [
              {
                LHS: 'is_scope_creator(n)', 
                RHS: 'template(n)=\'given\' | template(n)=\'assumption\'',
                description: 'a',
              }, {
                LHS: 'is_in_scope(m,n)', 
                RHS: '(~is_scope_creator(m)&indentation(n)>=indentation(m)&~$k<=n.(k>=m&indentation(k)<indentation(m)))|(indentation(n)>indentation(m)&~$k<=n.(k>=m&indentation(k)<=indentation(m)))',
                description: 'b'
              }
            ]
          ), BASE_CONTROL_LANGUAGE.operators
        )
      )
    },
    'control_function_table_2': {
      expected: 'The function f has already been defined.',
      actual: buildControlFunctionTable(
        [
          {LHS: 'f(n)', RHS: 'indentation(n) - 2', description: ''},
          {LHS: 'f(n)', RHS: 'indentation(n) - 2', description: ''}
        ]
      ).failure
    },
    'parse_message_1': {
      expected: 'stuff {{p&q}} thingies',
      actual: displayControlMessage(parseMessage('stuff {{p&q}} thingies', 'control'), BASE_CONTROL_LANGUAGE.operators)
    },
    'parse_message_2': {
      expected: JSON.stringify([{
        isFixed: true,
        content: 'Your use of '
      }, {
        isFixed: false,
        content: 'item'
      }, {
        isFixed: true,
        content: ' is wrong.'
      }]),
      actual: JSON.stringify(parseMessage('Your use of {{item}} is wrong.', 'general'))
    },
    'parse_message_3': {
      error: 'It was not possible to parse {{p[[x->a]}}.',
      actual: function() {
        parseMessage('By lack of arbitraryness this fails for {{p[[x->a]}}.', 'line');
      }
    },
    'parse_message_4': {
      error: 'This has an unmatched {{.',
      actual: function() {
        parseMessage('of {{result(scoper(n))}}.{{d)', 'control')
      }
    }
  };

  $scope.testResults = [];
  for (var key in $scope.tests) {
    $scope.testResults.push({name: key, expected: 'passed'});
    if ($scope.tests[key].hasOwnProperty('error')) {
      try {
        $scope.tests[key].actual();
        $scope.testResults[$scope.testResults.length-1].expected = 'An error should have occurred and did not.'
      }
        catch(err) {
          var actual = renderError(err, DEFAULT_ERROR_MESSAGES, BASE_STUDENT_LANGUAGE);
          if (actual !== $scope.tests[key].error) {
            $scope.testResults[$scope.testResults.length-1].expected =  $scope.tests[key].error;
            $scope.testResults[$scope.testResults.length-1].actual =  actual;    
          }
        }
    } else {
      if ($scope.tests[key].expected !== $scope.tests[key].actual) {
        $scope.testResults[$scope.testResults.length-1].expected =  $scope.tests[key].expected;
        $scope.testResults[$scope.testResults.length-1].actual =  $scope.tests[key].actual;      
      }
    }
  }
}

